
(** 
    This module provides a functional API to the 
    {{:http://perso.ens-lyon.fr/nathalie.revol/mpfi.html}
    MPFI interval arithmetic library}.

    The C code is organized as a memory pool.  The argument
    [size] of [initialize size] specifies the size of each pool.
    A memory pool is roughly a collection of arrays of intervals.
    An OCaml value of type [mpfi] is a pointer into one of the
    pools, and specifies a unique interval.  When all the pointers
    pointing into a pool have been garbage collected, the
    pool is deallocated.  
    
    One might need to experiment with the size of the memory pools
    for a given application.  As the code stands, all pools are
    of the same size.

    @author Sean McLaughlin
 *)

type mpfi
    (**
       The abstract type of intervals.  In fact, a pointer into
       a memory pool.
     *)

val set_gc_values : used:int -> max:int -> unit
  (** 
      Used for tuning the caml_alloc_custom function.
      In this case for intervals in the C heap.
      See section 18.9.2 of the OCaml manual for a description.
   *)

val of_string : string -> mpfi
  (** 
      The only [mpfi] constructor.  Because of the unsafe things 
      compilers and interpreters do with rounding modes and floating
      point numbers, we pass the constant we want to define directly
      to MPFI as a string.  MPFI handles the string parsing and
      rounding correctly.

      The string is of the form `M@N' or, alternatively `MeN' or `MEN'.
      `M' is the mantissa and `N' is the exponent.
      The mantissa and exponent are specified in decimal.
   *) 

val to_string : mpfi -> string
  (** 
      An approximation of the interval by a string, for display
      purposes.
   *) 

val raw_string : mpfi -> string

val print : mpfi -> unit
  (** 
      Print an interval on stdout. 
   *) 


(* functions *)
val add : mpfi -> mpfi -> mpfi
  (**
     Addition.
   *)

val sub : mpfi -> mpfi -> mpfi
  (**
     Subtraction.
   *)

val mul : mpfi -> mpfi -> mpfi
  (**
     Multiplication.
   *)

val div : mpfi -> mpfi -> mpfi
  (**
     Division.
   *)

val neg : mpfi -> mpfi
  (**
     Additive negation.
   *)

val lt : mpfi -> mpfi -> bool option
  (** 
      Comparison.  
      Returns [Some true] if every point of first interval is lower than 
      every point of second interval.  
      Returns [Some false] if every point of second interval is lower than 
      every point of the first interval.  
      Returns None if the intervals overlap.
   *)

val is_zero : mpfi -> bool
  (** True if interval contains only the element 0.0 *)

val inv : mpfi -> mpfi
  (**
     Multipliative inverse.
   *)

val sqr : mpfi -> mpfi
  (**
     The square, i.e. [sqr.x] = x^2
   *)

val sqrt : mpfi -> mpfi
  (**
     Square root.
   *)

val abs : mpfi -> mpfi
  (**
     Absolute value.
   *)

val log : mpfi -> mpfi
  (**
     Natural logarithm.
   *)

val sin : mpfi -> mpfi
  (**
     Sin.
   *)

val cos : mpfi -> mpfi
  (**
     Cosine.
   *)

val tan : mpfi -> mpfi
  (**
     Tangent.
   *)

val asin : mpfi -> mpfi
  (**
     Arcsin.
   *)

val acos : mpfi -> mpfi
  (**
     Arccosine.
   *)

val atan : mpfi -> mpfi
  (**
     Arctangent.
   *)

val pi : mpfi
  (** 
      The constant pi.
   *)

val bisect : mpfi -> mpfi * mpfi
  (** 
      Split an interval into two rougly equal pieces such
      that the union of the two output intervals covers the input
      interval.
   *) 

val union : mpfi -> mpfi -> mpfi
  (** 
      Union.
   *) 

val width : mpfi -> float
  (** 
      The approximate width.
   *) 

val iwidth : mpfi -> mpfi
  (** 
      The approximate width.
   *) 

val has_zero : mpfi -> bool
  (** 
      Whether 0 is contained in the interval.
   *) 

val nan_p : mpfi -> bool
  (**
     Returns [true] if the interval is not a number (NaN) in
     the sense of the IEEE floating point specification.
   *)

val inf_p : mpfi -> bool
  (**
     Returns [true] if the interval is infinite in
     the sense of the IEEE floating point specification.
   *)

val bounded_p : mpfi -> bool
  (**
     Returns [true] if the interval is bounded (finite)
   *)

val is_empty : mpfi -> bool
  (**
     Returns [true] if the interval is empty (endpoints are identical).
   *)

val lower : mpfi -> float
  (**
     The lower (left) endpoint of an interval.
   *)

val ilower : mpfi -> mpfi
  (**
     The lower (left) endpoint of an interval.
   *)

val upper : mpfi -> float
  (**
     The upper (right) endpoint of an interval.
   *)

val iupper : mpfi -> mpfi
  (**
     The upper (right) endpoint of an interval.
   *)

val is_strictly_pos : mpfi -> bool
  (**
     Whether each point in the interval is greater than 0.
   *)

val center : mpfi -> float
  (**
     The approximate center of the interval.
   *)

val icenter : mpfi -> mpfi
  (**
     The approximate center of the interval, as an interval.
   *)

val mem : mpfi -> float -> bool
  (**
     [mem v x] returns [true] if [x] is contained in [v].
   *)

val is_inside : mpfi -> mpfi -> bool
  (**
     [is_inside v1 v2] returns [true] if [v1] is contained in [v2].
   *)


val debug : bool -> unit
  (**
     Turn on rough debugging output for the C library.
   *)

val allocated_locations : unit -> int
  (**
     Implementation detail: how many slots for intervals
     are currently allocated on the C heap.
     This number should always be a multiple of 
     the pool size.
   *)

val used_locations : unit -> int
  (**
     Implementation detail: how many slots for intervals
     are active (i.e. reachable from OCaml).
     This should always be smaller than [allocated_locations].
     If the ration of used/allocated becomes very small, this
     indicates that there is fragmentation: i.e. there are
     a small number of active intervals in each memory pool.
     In this case, we might need to implement a [compact] 
     function, but the details are a bit scary, so we'll leave
     things as they are for now.
   *)


